
#include "talk/examples/crossfirewall/cfcallmanager.h"

using namespace talk_base;
namespace cricket {

	CFCallManager::CFCallManager(const buzz::Jid& local_jid, buzz::XmppClient* xmpp_client, bool bhttpallocator)
		: local_jid_(local_jid)
	{
		cmd_thread_ = NULL;
		cmd_console_ = NULL;

		std::string client_unique = local_jid.Str();
		talk_base::InitRandom(client_unique.c_str(), client_unique.size());
		cfsession_client_ = new cricket::CFSessionClient(xmpp_client, bhttpallocator);
		cfsession_client_->SignalSessionIncoming.connect(this, &CFCallManager::OnSessionIncoming);
		cfsession_client_->SignalSessionDestroy.connect(this, &CFCallManager::OnSessionDestroy);
	}

	CFCallManager::~CFCallManager()
	{
		if(cfsession_client_) { delete cfsession_client_;  cfsession_client_ = NULL; }
	}

	void CFCallManager::SetCmdWayToCore(talk_base::Thread* cmd_thread, CmdConsole* cmd_console)
	{
		if(cmd_thread)  cmd_thread_  = cmd_thread;
		if(cmd_console) cmd_console_ = cmd_console;
	}

	/******************************************************************************/
	/*******************************************************************************
                              Call Related function
	*******************************************************************************/
	/******************************************************************************/
	void CFCallManager::MakeCall(std::string remote_jid)
	{
		talk_base::CritScope cs(&callmanager_crit_);
		CFCall *call = CreateCall(remote_jid);
		call->MakeCall();
	}

	void CFCallManager::HangupCall(std::string remote_jid)
	{
		talk_base::CritScope cs(&callmanager_crit_);
		CallMap::iterator iter = call_map_.find(remote_jid);
		if(iter != call_map_.end()){
			//STR_LOG(INFO)<<"CFCallManager::HangupCall("<<remote_jid.c_str()<<").";
			iter->second->HangUpCall();
		}
	}
	
	void CFCallManager::DestroyCall(std::string remote_jid)
	{
		talk_base::CritScope cs(&callmanager_crit_);
		CallMap::iterator iter = call_map_.find(remote_jid);
		if(iter != call_map_.end()){
			//STR_LOG(INFO)<<"CFCallManager::DestroyCall("<<remote_jid.c_str()<<").";
			delete (iter->second);
			call_map_.erase(iter);
		}
	}

	void CFCallManager::HangupCallAll()
	{
		//STR_LOG(INFO)<<"CFCallManager::HangupCallAll().";
		talk_base::CritScope cs(&callmanager_crit_);
		CallMap::iterator iter = call_map_.begin();
		while(iter != call_map_.end()){
			iter->second->HangUpCall();
			iter++;
		}
	}

	CFCall *CFCallManager::CreateCall(std::string remote_jid)
	{
		//STR_LOG(INFO)<<"CFCallManager::CreateCall("<<remote_jid.c_str()<<").";
		CFCall *call = call = new CFCall(local_jid_.Str(), remote_jid, cfsession_client_);
		SignalCallStateChange(call, remote_jid, STR_CALL_STATE_INIT);
		call->SignalCallStateChange.connect(this, &CFCallManager::OnCallStateChange);
		call_map_[remote_jid] = call;
		return call;
	}	
	
	void CFCallManager::OnCallStateChange(CFCall* call, std::string remote_jid, int state)
	{
		SignalCallStateChange(call, remote_jid, state);
	}

	/******************************************************************************/
	/*******************************************************************************
                            Session Related function
	*******************************************************************************/
	/******************************************************************************/
	void CFCallManager::OnSessionIncoming(Session* session)
	{
		talk_base::CritScope cs(&callmanager_crit_);
		std::string remote_jid = session->remote_name();

		CallMap::iterator iter = call_map_.find(remote_jid);
		if(iter != call_map_.end())
			iter->second->OnSessionIncoming(session);
		else{
			CFCall *call = CreateCall(remote_jid);
			call->OnSessionIncoming(session);
		}
	}

	void CFCallManager::OnSessionDestroy(Session* session)
	{
		talk_base::CritScope cs(&callmanager_crit_);
		std::string remote_jid = session->remote_name();

		CallMap::iterator iter = call_map_.find(remote_jid);
		if(iter != call_map_.end())
			iter->second->OnSessionDestroy(session);
	}
}